#define _POSIX_C_SOURCE 200809L
#include <sys/wait.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

int system(char * cmdstring) {
    struct sigaction ignore, sigint, sigquit;
    sigset_t newmask, oldmask;
    int status;
    pid_t pid;

    if (!cmdstring)
        return 1;

    ignore.sa_handler= SIG_IGN;
    sigemptyset(&ignore.sa_mask);
    ignore.sa_flags = 0;
    if (sigaction(SIGINT, &ignore, &sigint) < 0)
        return -1;
    if (sigaction(SIGQUIT, &ignore, &sigquit) < 0)
        return -1;
    
    sigemptyset(&newmask);
    sigaddset(&newmask, SIGCHLD);
    if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
        return -1;

    if ((pid= fork()) < 0)
        return -1;
    else if (pid == 0) {
        /* restore previous signal actions & reset signal mask */
        sigaction(SIGINT, &sigint, NULL);
        sigaction(SIGQUIT, &sigquit, NULL);
        sigprocmask(SIG_SETMASK, &oldmask, NULL);
        execl("/bin/sh", "sh", "-c", cmdstring, NULL);
        _exit(127);
    }

    while (waitpid(pid, &status, 0) < 0) {  // 在取得子进程状态 或 EINTR(信号中断)时退出，而ECHILD 只在所有子进程状态获取后才会出现
            if (errno != EINTR) {
                status= -1; 
                break;
            }
    }

    if (sigaction(SIGINT, &sigint, NULL) < 0)
        return -1;
    if (sigaction(SIGQUIT, &sigquit, NULL) < 0)
        return -1;
    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
        return -1;

    return status;
}

